package solution;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;

import task.Official;
import task.Official.Color;

public class BoardImpl implements task.Board{

	private int width;
	private int height;
	ArrayList<ArrayList <Field>> board ;
	
	private boolean checkWidth(int width){
		if(width >255){
		}
		return true;
	}
	private boolean checkHeight(int height){
		if(height >255){
		}
		return true;
	}
	public BoardImpl(int width, int height){
		
		assertTrue(checkWidth(width));
		assertTrue(checkHeight(height));

		this.width = width;
		this.height = height;
		this.board = new ArrayList<ArrayList <Field>>();
		for(int i =0; i < width; i++){
			ArrayList<Field> row = new ArrayList<Field>();
			for ( int j = 0 ; j < height ; j++){
				row.add(new Field(i, j, this));
			}
			board.add(row);
		}
	}
	
	public BoardImpl(ArrayList<ArrayList <Field>> board) {
		this.board = board;
	}

	public OfficialImpl addOfficial(int x, int y, Color robe, Color hat) {

		assertTrue(checkWidth(x));
		assertTrue(checkHeight(y));
		Field field = board.get(x).get(y);
		if (!field.isBlocked() && !field.isOccupied()){
			OfficialImpl official = new OfficialImpl(robe, hat, field);
			field.setOfficial(official);
			System.out.println("Official has been added.");
			return official;
		}
		else return null;
	}
	public Official getOfficial(int x, int y) {
		
		Field field = board.get(x).get(y);
		return field.getOfficial();
	}
	
	public Official getOfficial(Color robe,Color hat) {
		
	
		for(int i=0; i < width;i++){
			for(int j =0; j < height;j++){
				Field field = board.get(i).get(j);
				if(field.isOccupied()){				
				Official official =	field.getOfficial();
				if(official.getHat().equals(hat)&& official.getRobe().equals(robe)){
					return official;
					}
				
				}
				continue;
			}
		}
		 return null;
	}
	
	public Field getField(int x, int y){
		return board.get(x).get(y);
	}

	public void addBlock(int x, int y) {
		if (x >= width ||y >= height){
			throw new IllegalArgumentException("Block liegt nicht im Feld.");
		}
		else board.get(x).get(y).setBlocked(true);
	}

	public boolean hasBlock(int x, int y) {
		return board.get(x).get(y).isBlocked();
	}

	public void addWallNorth(int x, int y) {
		if(!hasWallNorth(x,y)){
		addWall(x, y, 0);
		}
	}
	
	public void addWallEast(int x, int y) {
		if(!hasWallEast(x,y)) {
		addWall(x, y, 1);
		}
	}

	public void addWallSouth(int x, int y) {
		if(!hasWallSouth(x,y)){
		addWall(x, y, 2);
		}
	}

	public void addWallWest(int x, int y) {
		if(!hasWallSouth(x,y)){
		addWall(x, y, 3);
		}
	}
	
	private void addWall(int x, int y, int orientation){
		board.get(x).get(y).setWall(orientation, true);
		addWallAtNeighbor(x, y);
	}
	
	private void addWallAtNeighbor(int x, int y){
		
		if(hasWallNorth(x,y)){
			addWallSouth(x,y+1);
		}
		if(hasWallSouth(x,y)){
			addWallNorth(x,y-1);
		}
		if(hasWallWest(x,y)){
			addWallEast(x-1,y);
		}
		if(hasWallEast(x,y)){
			addWallWest(x+1,y);
		}
	}

	public boolean hasWallNorth(int x, int y) {
		return hasWall(x, y, 0);
	}


	public boolean hasWallEast(int x, int y) {
		return hasWall(x, y, 1);
	}

	public boolean hasWallSouth(int x, int y) {
		return hasWall(x, y, 2);
	}

	public boolean hasWallWest(int x, int y) {
		return hasWall(x, y, 3);
	}
	
	private boolean hasWall(int x, int y, int orientation){
		return board.get(x).get(y).hasWall(orientation);
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	private int getDistance() {
		return Integer.MAX_VALUE;
	}


	public ArrayList<ArrayList <Field>> getBoard() {
		return board;
	}
	
	public void moveOfficial(int fromX, int fromY, int toX, int toY){
		Official official = getOfficial(fromX, fromY);
		getField(fromX, fromY).setOfficial(null);
		getField(toX, toY).setOfficial(official);
		
	}
	

	@Override
	public int getDistance(Official official, int x, int y) {
		return 0;
	}
}
